package com.wzh.codegen.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wzh.codegen.api.domain.dto.TableConfigQuery;
import com.wzh.codegen.biz.domain.dto.CodegenColumnDTO;
import com.wzh.codegen.biz.domain.dto.CodegenTableConfigDTO;
import com.wzh.codegen.biz.domain.dto.DatasourceDTO;
import com.wzh.codegen.biz.domain.dto.GenerateOptionsDTO;
import com.wzh.codegen.biz.domain.entity.CodegenTableConfig;
import com.wzh.codegen.biz.mapper.CodegenTableConfigMapper;
import com.wzh.codegen.biz.service.CodegenTableConfigService;
import com.wzh.codegen.biz.service.DatasourceService;
import com.wzh.codegen.biz.util.CodegenUtils;
import com.wzh.codegen.biz.util.DatabaseUtils;
import com.wzh.common.general.exception.CustomerException;
import com.wzh.common.general.result.PageQuery;
import com.wzh.common.general.result.PageResult;
import com.wzh.common.mybatis.util.MybatisPageUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.util.Asserts;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;

/**
 * 代码生成表配置服务实现
 *
 * @author wzh
 * @since 2024-01-01
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CodegenTableConfigServiceImpl extends ServiceImpl<CodegenTableConfigMapper, CodegenTableConfig> implements CodegenTableConfigService {

    private final ObjectMapper objectMapper;
    private final DatasourceService datasourceService;
    private final DatabaseUtils databaseUtils;

    @Override
    public Long saveTableConfig(CodegenTableConfigDTO dto) {
        try {
            CodegenTableConfig entity = new CodegenTableConfig();
            BeanUtils.copyProperties(dto, entity);

            // 序列化字段配置
            if (dto.getColumns() != null) {
                entity.setColumnsConfig(objectMapper.writeValueAsString(dto.getColumns()));
            }

            // 序列化生成选项
            if (dto.getGenerateOptionsDTO() != null) {
                entity.setGenerateOptions(objectMapper.writeValueAsString(dto.getGenerateOptionsDTO()));
            }

            // 设置状态为已保存
            entity.setStatus(1);

            saveOrUpdate(entity);
            log.info("保存表配置成功，表名: {}, ID: {}", dto.getTableName(), entity.getId());
            return entity.getId();
        } catch (Exception e) {
            log.error("保存表配置失败", e);
            throw new CustomerException("保存表配置失败: " + e.getMessage());
        }
    }

    @Override
    public void updateTableConfig(CodegenTableConfigDTO dto) {
        try {
            if (dto.getId() == null) {
                throw new CustomerException("配置ID不能为空");
            }

            CodegenTableConfig entity = getById(dto.getId());
            if (entity == null) {
                throw new CustomerException("表配置不存在");
            }

            BeanUtils.copyProperties(dto, entity);

            // 序列化字段配置
            if (dto.getColumns() != null) {
                entity.setColumnsConfig(objectMapper.writeValueAsString(dto.getColumns()));
            }

            // 序列化生成选项
            if (dto.getGenerateOptionsDTO() != null) {
                entity.setGenerateOptions(objectMapper.writeValueAsString(dto.getGenerateOptionsDTO()));
            }

            updateById(entity);
            log.info("更新表配置成功，表名: {}, ID: {}", dto.getTableName(), entity.getId());
        } catch (Exception e) {
            log.error("更新表配置失败", e);
            throw new CustomerException("更新表配置失败: " + e.getMessage());
        }
    }

    @Override
    public List<CodegenTableConfigDTO> getTableConfigs(Long datasourceId) {
        try {
            LambdaQueryWrapper<CodegenTableConfig> queryWrapper = new LambdaQueryWrapper<>();
            if (datasourceId != null) {
                queryWrapper.eq(CodegenTableConfig::getDatasourceId, datasourceId);
            }
            queryWrapper.orderByDesc(CodegenTableConfig::getUpdateTime);

            List<CodegenTableConfig> entities = list(queryWrapper);
            return entities.stream().map(this::convert).toList();
        } catch (Exception e) {
            log.error("获取表配置列表失败", e);
            throw new CustomerException("获取表配置列表失败: " + e.getMessage());
        }
    }

    @Override
    public PageResult<CodegenTableConfigDTO> pageTableConfigs(PageQuery<TableConfigQuery> pageQuery) {
        Page<CodegenTableConfig> page = MybatisPageUtils.createPage(pageQuery);

        // 处理排序
        LambdaQueryWrapper<CodegenTableConfig> queryWrapper = MybatisPageUtils.handleOrderByAndQueryLambda(pageQuery, "create_time");

        Page<CodegenTableConfig> result = this.page(page, queryWrapper);

        return MybatisPageUtils.toPageResult(result, this::convert);
    }


    @Override
    public CodegenTableConfigDTO getTableConfig(Long id) {
        try {
            CodegenTableConfig entity = getById(id);
            if (entity == null) {
                throw new CustomerException("表配置不存在");
            }
            return convert(entity);
        } catch (Exception e) {
            log.error("获取表配置详情失败", e);
            throw new CustomerException("获取表配置详情失败: " + e.getMessage());
        }
    }

    @Override
    public void deleteTableConfig(Long id) {
        try {
            CodegenTableConfig entity = getById(id);
            if (entity == null) {
                throw new CustomerException("表配置不存在");
            }

            removeById(id);
            log.info("删除表配置成功，表名: {}, ID: {}", entity.getTableName(), id);
        } catch (Exception e) {
            log.error("删除表配置失败", e);
            throw new CustomerException("删除表配置失败: " + e.getMessage());
        }
    }

    @Override
    public void batchDeleteTableConfigs(List<Long> ids) {
        try {
            removeByIds(ids);
            log.info("批量删除表配置成功，数量: {}", ids.size());
        } catch (Exception e) {
            log.error("批量删除表配置失败", e);
            throw new CustomerException("批量删除表配置失败: " + e.getMessage());
        }
    }

    @Override
    public CodegenTableConfigDTO getTableConfigByDatasourceAndTable(Long datasourceId, String tableName) {
        try {
            LambdaQueryWrapper<CodegenTableConfig> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(datasourceId != null, CodegenTableConfig::getDatasourceId, datasourceId)
                    .eq(datasourceId != null, CodegenTableConfig::getTableName, tableName)
                    .last("LIMIT 1");

            CodegenTableConfig entity = getOne(queryWrapper);
            return entity != null ? convert(entity) : null;
        } catch (Exception e) {
            log.error("根据数据源和表名获取配置失败", e);
            throw new CustomerException("获取表配置失败: " + e.getMessage());
        }
    }

    /**
     * 实体转DTO
     */
    private CodegenTableConfigDTO convert(CodegenTableConfig entity) {
        try {
            CodegenTableConfigDTO dto = MybatisPageUtils.convert(entity, CodegenTableConfigDTO.class);

            // 反序列化字段配置
            if (StringUtils.hasText(entity.getColumnsConfig())) {
                List<CodegenColumnDTO> columns = objectMapper.readValue(
                        entity.getColumnsConfig(),
                        new TypeReference<>() {
                        }
                );
                dto.setColumns(columns);
            }

            // 反序列化生成选项
            if (StringUtils.hasText(entity.getGenerateOptions())) {
                GenerateOptionsDTO options = objectMapper.readValue(
                        entity.getGenerateOptions(),
                        GenerateOptionsDTO.class
                );
                dto.setGenerateOptionsDTO(options);
            }

            return dto;
        } catch (Exception e) {
            log.error("转换DTO失败", e);
            throw new CustomerException("转换DTO失败: " + e.getMessage());
        }
    }

    @Override
    public Long importTableFromDatabase(Long datasourceId, String tableName) {
        try {
            // 检查表配置是否已存在
            CodegenTableConfigDTO existingConfig = getTableConfigByDatasourceAndTable(datasourceId, tableName);
            if (existingConfig != null) {
                throw new CustomerException("表配置已存在，请使用更新功能");
            }

            // 获取数据源信息
            DatasourceDTO datasource = MybatisPageUtils.convert(datasourceService.getById(datasourceId), DatasourceDTO.class);
            Asserts.notNull(datasource, "数据源不存在");

            // 获取数据库表信息
            List<Map<String, Object>> tables = databaseUtils.getTables(datasource);
            Map<String, Object> tableInfo = tables.stream()
                    .filter(table -> tableName.equals(table.get("tableName")))
                    .findFirst()
                    .orElseThrow(() -> new CustomerException("表不存在: " + tableName));

            // 获取表字段信息
            List<Map<String, Object>> columnInfos = databaseUtils.getTableColumns(datasource, tableName);

            // 转换为CodegenColumnDTO
            List<CodegenColumnDTO> columns = columnInfos.stream().map(columnInfo -> {
                CodegenColumnDTO column = new CodegenColumnDTO();
                column.setColumnName((String) columnInfo.get("columnName"));
                column.setColumnType((String) columnInfo.get("dataType"));
                column.setColumnLength((Integer) columnInfo.get("columnSize"));
                column.setColumnScale((Integer) columnInfo.get("decimalDigits"));
                column.setColumnComment((String) columnInfo.get("columnComment"));
                column.setIsPrimaryKey((Boolean) columnInfo.get("isPrimaryKey"));
                column.setIsAutoIncrement((Boolean) columnInfo.get("isAutoIncrement"));
                column.setIsNullable((Boolean) columnInfo.get("nullable"));
                column.setDefaultValue((String) columnInfo.get("columnDefault"));
                column.setJavaFieldName((String) columnInfo.get("javaFieldName"));
                column.setJavaFieldType((String) columnInfo.get("javaFieldType"));

                // 设置默认的显示和查询配置
                column.setShowInList(!isCommonField(column.getColumnName()));
                column.setShowInForm(!isCommonField(column.getColumnName()) && !column.getIsPrimaryKey());
                column.setShowInQuery(false);
                column.setQueryType("=");
                column.setFormType(getDefaultFormType(column.getJavaFieldType()));

                return column;
            }).toList();

            // 创建表配置DTO
            CodegenTableConfigDTO dto = new CodegenTableConfigDTO();
            String serviceNameCamelCase = CodegenUtils.toCamelCase(tableName);
            String serviceNameTo = CodegenUtils.capitalize(tableName);
            dto.setDatasourceId(datasourceId);
            dto.setTableName(tableName);
            dto.setTableComment((String) tableInfo.get("tableComment"));
            dto.setEntityName(serviceNameTo);
            dto.setPackageName("com.wzh." + serviceNameCamelCase);
            dto.setGeneratePath("/tmp/codegen");
            dto.setAuthor("system");
            dto.setColumns(columns);
            // 已保存状态
            dto.setStatus(1);

            // 设置默认生成选项
            GenerateOptionsDTO generateOptions = new GenerateOptionsDTO();
            dto.setGenerateOptionsDTO(generateOptions);

            // 保存表配置
            Long configId = saveTableConfig(dto);
            log.info("从数据库导入表配置成功，表名: {}, 配置ID: {}", tableName, configId);
            return configId;
        } catch (Exception e) {
            log.error("从数据库导入表配置失败", e);
            throw new CustomerException("从数据库导入表配置失败: " + e.getMessage());
        }
    }

    /**
     * 判断是否为通用字段
     */
    static boolean isCommonField(String columnName) {
        return "id".equals(columnName) || "create_time".equals(columnName) ||
                "update_time".equals(columnName) || "create_by".equals(columnName) ||
                "update_by".equals(columnName) || "del_flag".equals(columnName);
    }

    /**
     * 根据Java类型获取默认表单类型
     */
    static String getDefaultFormType(String javaType) {
        if ("String".equals(javaType)) {
            return "input";
        } else if ("Integer".equals(javaType) || "Long".equals(javaType) || "BigDecimal".equals(javaType)) {
            return "number";
        } else if ("LocalDateTime".equals(javaType) || "Date".equals(javaType)) {
            return "datetime";
        } else if ("Boolean".equals(javaType)) {
            return "switch";
        }
        return "input";
    }
}